package utils;

import java.util.Arrays;
import java.util.Objects;

/**
 * 节点工具类
 */
public class Digital implements Comparable<Digital> {
    /**
     * 存储表格
     */
    public int[][] board;
    /**
     * 存储和标准结果的差距
     */
    public int flag;

    /**
     * 统计是第几步了
     */
    public int step;
    /**
     * 存储空格的位置
     */
    public int x;
    public int y;

    Digital() {
        board = new int[3][3];
        flag = 8;
        x = 0;
        y = 0;
    }

    public Digital(int[][] board) {
        this.board = board;
    }

    /**
     * 获取当前状态向上移动一位的结果
     *
     * @return 新的对象，如果不存在则为null
     */
    public Digital up() {
        if (x == 0) {
            return null;
        }

        Digital tmp = new Digital();
        for (int i = 0; i < 3; i++) {
            System.arraycopy(this.board[i], 0, tmp.board[i], 0, 3);
        }
        tmp.board[x][y] = tmp.board[x - 1][y];
        tmp.board[x - 1][y] = 0;
        tmp.x = this.x - 1;
        tmp.y = this.y;
        tmp.step = this.step + 1;

        return tmp;
    }

    /**
     * 向下
     *
     * @return
     */
    public Digital down() {
        if (x == 2) {
            return null;
        }

        Digital tmp = new Digital();
        for (int i = 0; i < 3; i++) {
            System.arraycopy(this.board[i], 0, tmp.board[i], 0, 3);
        }
        tmp.board[x][y] = tmp.board[x + 1][y];
        tmp.board[x + 1][y] = 0;
        tmp.x = this.x + 1;
        tmp.y = this.y;
        tmp.step = this.step + 1;

        return tmp;
    }

    /**
     * 向左
     *
     * @return
     */
    public Digital left() {
        if (y == 0) {
            return null;
        }

        Digital tmp = new Digital();
        for (int i = 0; i < 3; i++) {
            System.arraycopy(this.board[i], 0, tmp.board[i], 0, 3);
        }
        tmp.board[x][y] = tmp.board[x][y - 1];
        tmp.board[x][y - 1] = 0;
        tmp.x = this.x;
        tmp.y = this.y - 1;
        tmp.step = this.step + 1;

        return tmp;
    }

    /**
     * 向右
     *
     * @return
     */
    public Digital right() {
        if (y == 2) {
            return null;
        }

        Digital tmp = new Digital();
        for (int i = 0; i < 3; i++) {
            System.arraycopy(this.board[i], 0, tmp.board[i], 0, 3);
        }
        tmp.board[x][y] = tmp.board[x][y + 1];
        tmp.board[x][y + 1] = 0;
        tmp.x = this.x;
        tmp.y = this.y + 1;
        tmp.step = this.step + 1;

        return tmp;
    }

    /**
     * 设置其与标准状态的差距的值
     * @param target 标准状态
     */
    public void setCount(Digital target) {
        int count = 0;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (this.board[i][j] != target.board[i][j]) {
                    count++;
                }
            }
        }
        this.flag = count;
    }

    /**
     * 重写equals函数，只要两个对象中数据一样就相同
     *
     * @param o 要判断的对象
     * @return 判断结果
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Digital digital = (Digital) o;

        boolean res = flag == digital.flag;
        for (int i = 0; i < 3 && res; i++) {
            res = Arrays.equals(board[i], digital.board[i]);
        }
        return res;
    }

    /**
     * 重写hashCode函数，只要表格相同，得到的hash值就相同
     *
     * @return
     */
    @Override
    public int hashCode() {
        int result = Arrays.hashCode(board[0]) * 2;
        result += Arrays.hashCode(board[1]) * 3 + Arrays.hashCode(board[2]) * 7;
        return result;
    }

    /**
     * 因为要根据flag的值进行排序，所以就实现接口，重写函数
     * @param o 要对比的对象
     * @return 大于返回1，等于返回0，小于返回-1
     */
    @Override
    public int compareTo(Digital o) {
        return Integer.compare(this.flag+this.step, o.flag+o.step);
    }

    @Override
    public String toString() {
        return "Digital{" +
                "board=" + Arrays.toString(board[0]) + ", " + Arrays.toString(board[1])+ ", " + Arrays.toString(board[2]) +
                ", flag=" + flag +
                ", step=" + step +
                ", x=" + x +
                ", y=" + y +
                '}';
    }

}
